package com.ledi.guns.core.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;

import com.ledi.guns.core.exception.GunsException;
import com.ledi.guns.core.exception.GunsExceptionEnum;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.region.Region;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.Upload;

@Slf4j
public class FileUtil {

	/**
	 * NIO way
	 */
	public static byte[] toByteArray(String filename) {

		File f = new File(filename);
		if (!f.exists()) {
			log.error("文件未找到！" + filename);
			throw new GunsException(GunsExceptionEnum.FILE_NOT_FOUND);
		}
		FileChannel channel = null;
		FileInputStream fs = null;
		try {
			fs = new FileInputStream(f);
			channel = fs.getChannel();
			ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
			while (channel.read(byteBuffer) > 0) {
				// do nothing
				// System.out.println("reading");
			}
			return byteBuffer.array();
		} catch (IOException e) {
			throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR);
		} finally {
			try {
				channel.close();
			} catch (IOException e) {
				throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR);
			}
			try {
				fs.close();
			} catch (IOException e) {
				throw new GunsException(GunsExceptionEnum.FILE_READING_ERROR);
			}
		}
	}

	/**
	 * 方法描述: [这里用一句话描述这个方法的作用.]<br/>
	 * [这里描述这个方法适用条件 – 可选.]<br/>
	 * [这里描述这个方法的执行流程 – 可选.]<br/>
	 * [这里描述这个方法的使用方法 – 可选.]<br/>
	 * [这里描述这个方法的注意事项 – 可选.]<br/>
	 * 初始作者: 钟小平<br/>
	 * 创建日期: 2018年9月14日-上午11:28:35<br/>
	 * 开始版本: 2.0.0<br/>
	 * =================================================<br/>
	 * 修改记录：<br/>
	 * 修改作者 日期 修改内容<br/>
	 * ================================================<br/>
	 * 
	 * @param multipartFile
	 * @param fileType
	 * @param cosSecretId
	 * @param cosSecretKey
	 * @param cosBucketName
	 * @param cosAppid
	 * @return
	 * @throws IOException
	 *             String
	 */
	public static String uploadFile(MultipartFile multipartFile, String fileType, String cosSecretId, String cosSecretKey, String cosBucketName, String cosAppid)
			throws IOException {

		// 1 初始化用户身份信息(secretId, secretKey)
		COSCredentials cred = new BasicCOSCredentials(cosSecretId, cosSecretKey);
		// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
		ClientConfig clientConfig = new ClientConfig(new Region("ap-shanghai"));
		// 3 生成cos客户端
		COSClient cosclient = new COSClient(cred, clientConfig);
		// bucket名需包含appid
		String bucketName = cosBucketName + "-" + cosAppid;
		// url = url.replaceAll("\\", "/");

		String key = createUploadLinuxPath(fileType, "file");

		String temp = FileUtils.getTempDirectoryPath();
		String url = temp + key;
		File file = new File(url);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		inputStreamtofile(multipartFile.getInputStream(), file);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		ExecutorService threadPool = Executors.newFixedThreadPool(32);
		// 传入一个threadpool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosclient, threadPool);

		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
		// 本地文件上传

		try {

			Upload upload = transferManager.upload(putObjectRequest);
			upload.waitForCompletion();

		} catch (CosServiceException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} catch (CosClientException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} catch (InterruptedException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} finally {
			file.delete();
			transferManager.shutdownNow();
			cosclient.shutdown();
		}
		log.info("文件{}上传成功", key);
		return key;
	}

	/**
	 * 方法描述: [这里用一句话描述这个方法的作用.]<br/>
	 * [这里描述这个方法适用条件 – 可选.]<br/>
	 * [这里描述这个方法的执行流程 – 可选.]<br/>
	 * [这里描述这个方法的使用方法 – 可选.]<br/>
	 * [这里描述这个方法的注意事项 – 可选.]<br/>
	 * 初始作者: 钟小平<br/>
	 * 创建日期: 2018年9月14日-上午11:28:46<br/>
	 * 开始版本: 2.0.0<br/>
	 * =================================================<br/>
	 * 修改记录：<br/>
	 * 修改作者 日期 修改内容<br/>
	 * ================================================<br/>
	 * 
	 * @param input
	 * @param fileType
	 * @param cosSecretId
	 * @param cosSecretKey
	 * @param cosBucketName
	 * @param cosAppid
	 * @return
	 * @throws IOException
	 *             String
	 */
	public static String uploadFile(InputStream input, String fileType, String cosSecretId, String cosSecretKey, String cosBucketName, String cosAppid) throws IOException {

		// 1 初始化用户身份信息(secretId, secretKey)
		COSCredentials cred = new BasicCOSCredentials(cosSecretId, cosSecretKey);
		// 2 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
		ClientConfig clientConfig = new ClientConfig(new Region("ap-shanghai"));
		// 3 生成cos客户端
		COSClient cosclient = new COSClient(cred, clientConfig);
		// bucket名需包含appid
		String bucketName = cosBucketName + "-" + cosAppid;
		// url = url.replaceAll("\\", "/");

		String key = createUploadLinuxPath(fileType, "file");

		String temp = FileUtils.getTempDirectoryPath();
		String url = temp + key;
		File file = new File(url);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		inputStreamtofile(input, file);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		ExecutorService threadPool = Executors.newFixedThreadPool(32);
		// 传入一个threadpool, 若不传入线程池, 默认TransferManager中会生成一个单线程的线程池。
		TransferManager transferManager = new TransferManager(cosclient, threadPool);

		PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
		// 本地文件上传

		try {

			Upload upload = transferManager.upload(putObjectRequest);
			upload.waitForCompletion();

		} catch (CosServiceException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} catch (CosClientException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} catch (InterruptedException e) {
			e.printStackTrace();
			log.error(e.getMessage());
		} finally {
			file.delete();
			transferManager.shutdownNow();
			cosclient.shutdown();
		}
		log.info("文件{}上传成功", key);
		return key;
	}

	public static void inputStreamtofile(InputStream ins, File file) {

		OutputStream os = null;
		try {
			os = new FileOutputStream(file);
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			if (null != os) {
				os.close();
			}
			if (null != ins) {
				ins.close();
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != os) {

					os.close();

				}
				if (null != ins) {
					ins.close();

				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static String createUploadLinuxPath(String fileType, String packageName) {

		return "/" + packageName + "/" + TimeUtil.getYear() + "/" + TimeUtil.getMonth() + "/" + TimeUtil.getDay() + "/"
				+ java.util.UUID.randomUUID().toString() + "." + fileType;
	}
}
